package com.cww.study.config;


import com.cww.study.interceptor.ResponseBodyHandler;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: myes
 * @description:
 * @author: 陈英俊
 * @create: 2021-09-09 14:37
 */
@Component
public class WebMvcConfiguration extends WebMvcConfigurationSupport implements InitializingBean {


    /**
     * 请求映射处理器适配器
     */
    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;


    @Autowired
    private ResponseBodyHandler responseBodyHandler;

    /**
     * @return
     * @ConditionalOnMissingBean 修饰bean的一个注解，主要实现的是，当你的bean被注册之后，如果而注册相同类型的bean，就不会成功，
     * 它会保证你的bean只有一个，即你的实例只有一个，当你注册多个相同的bean时，会出现异常，以此来告诉开发人员。
     */
    @Bean
    @ConditionalOnMissingBean({ResponseBodyHandler.class})
    public ResponseBodyHandler jsonReturnHandler() {
        return new ResponseBodyHandler();
    }

    /**
     * 重写父类的方法,添加自定义的拦截器
     *
     * @param returnValueHandlers
     */
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        returnValueHandlers.add(this.responseBodyHandler);
    }


    /**
     * 实现了InitializingBean这个接口的类,在初始化Bean会执行这个方法,相当于初始化数据
     *
     * @throws Exception
     */
    public void afterPropertiesSet() throws Exception {
        // 查找出所有实现了HandlerMethodReturnValueHandler 接口的类集合,底层是返回的集合使用Collections.unmodifiableList(list),表示该集合无法修改操作,所以用新集合接受
        List<HandlerMethodReturnValueHandler> originalHandlers = new ArrayList(this.requestMappingHandlerAdapter.getReturnValueHandlers());
        // 判断哪个集合元素的父类是HttpEntityMethodProcessor,取出元素的索引
        int deferredPos = this.obtainValueHandlerPosition(originalHandlers, HttpEntityMethodProcessor.class);
        // 在list里面添加自定义的处理器
        originalHandlers.add(deferredPos - 1, this.responseBodyHandler);
        // 然后将新的list在重新set进去
        this.requestMappingHandlerAdapter.setReturnValueHandlers(originalHandlers);
    }

    private int obtainValueHandlerPosition(final List<HandlerMethodReturnValueHandler> originalHandlers, Class<?> handlerClass) {
        for (int i = 0; i < originalHandlers.size(); ++i) {
            HandlerMethodReturnValueHandler valueHandler = originalHandlers.get(i);
            // a.isAssignableFrom(b) 判断a是不是b的父类
            if (handlerClass.isAssignableFrom(valueHandler.getClass())) {
                return i;
            }
        }
        return -1;
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 前面是访问路径
        registry.addResourceHandler("/**").addResourceLocations("classpath:/dist/");
    }


    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("").setViewName("forward:/index.html");
        registry.addViewController("/").setViewName("forward:/index.html");
        registry.addViewController("/index").setViewName("forward:/index.html");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
    }
}
